package main

import (
	"log"
	"sync"
	"time"
)

// 无缓冲 channel：1对n通知信号，常用于协调多个 goroutine 一起工作

func worker(i int) {
	log.Printf("worker %d: is working...\n", i)
	time.Sleep(1 * time.Second)
	log.Printf("worker %d: works done\n", i)
}

type signal struct{}

func spawnGroup(f func(i int), num int, groupChannel <-chan signal) <-chan signal {
	ch := make(chan signal)
	var wg sync.WaitGroup

	for i := 0; i < num; i++ {
		wg.Add(1)
		go func(n int) {
			<-groupChannel // 所有的 worker goroutine 会在这里阻塞直到收到“通知信号”
			log.Printf("worker %d: start to work...\n", n)
			f(n)
			wg.Done()
		}(i + 1)
	}

	go func() {
		wg.Wait()      // 等待所有 worker goroutine 完成工作
		ch <- signal{} // 然后发送通知信号
	}()

	return ch
}

func main() {
	log.Println("start a group worker...")
	groupChannel := make(chan signal)

	// main goroutine 创建了一组 N 个 worker goroutine
	ch := spawnGroup(worker, 5, groupChannel)

	time.Sleep(5 * time.Second)

	log.Println("the group of workers start to work...")

	close(groupChannel) // 向所有 worker goroutine 广播“开始工作”的信号

	<-ch // main goroutine 阻塞这里，等待所有 worker goroutine 完成工作的通知信号

	log.Println("all worker work done")

}
